package cn.iocoder.yudao.module.trade.service.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.enums.metal.MetalTypeEnum;
import cn.iocoder.yudao.framework.common.enums.pay.PayChannelEnum;
import cn.iocoder.yudao.framework.common.enums.pay.PayOrderStatusEnum;
import cn.iocoder.yudao.framework.common.enums.pay.PayWalletBizTypeEnum;
import cn.iocoder.yudao.framework.common.enums.pay.PayWalletTypeEnum;
import cn.iocoder.yudao.framework.common.enums.trade.TradeOrderStatusEnum;
import cn.iocoder.yudao.framework.common.enums.trade.TradeSettleMethodTypeEnum;
import cn.iocoder.yudao.framework.common.enums.trade.TransactionTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.liveprice.api.LivePriceApi;
import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
import cn.iocoder.yudao.module.member.api.bankInfo.BankAccountInfoApi;
import cn.iocoder.yudao.module.member.api.bankInfo.dto.BankAccountInfoDTO;
import cn.iocoder.yudao.module.member.api.config.MemberConfApi;
import cn.iocoder.yudao.module.member.api.config.dto.*;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
import cn.iocoder.yudao.module.pay.api.wallet.PayWalletApi;
import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletAddBalanceReqDTO;
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO;
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderUpdateCheckDTO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDeliveryDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService;
import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
import cn.iocoder.yudao.module.trade.service.order.handler.TransactionModeHandler;
import cn.iocoder.yudao.module.trade.service.order.handler.TransactionModeHandlerFactory;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserName;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants.WXA_ORDER_DELIVERY;

/**
 * 交易订单【写】Service 实现类
 *
 * @author LeeYan9
 * @since 2022-08-26
 */
@Service
@Slf4j
public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {

    @Resource
    private TradeOrderMapper tradeOrderMapper;
    @Resource
    private TradeOrderItemMapper tradeOrderItemMapper;
    @Resource
    private TradeNoRedisDAO tradeNoRedisDAO;

    @Resource
    private List<TradeOrderHandler> tradeOrderHandlers;
    @Resource
    private DeliveryExpressService deliveryExpressService;
    @Resource
    private TradeMessageService tradeMessageService;
    @Resource
    private DeliveryPickUpStoreService pickUpStoreService;

    @Resource
    private PayOrderApi payOrderApi;
    @Resource
    private PayWalletApi payWalletApi;
    @Resource
    private MemberAddressApi addressApi;
    @Resource
    private MemberConfApi memberConfApi;
    @Resource
    public SocialClientApi socialClientApi;
    @Resource
    public PayRefundApi payRefundApi;

    @Resource
    private TradeOrderProperties tradeOrderProperties;

    @Resource
    private TransactionModeHandlerFactory transactionModeHandlerFactory;
    @Resource
    private LivePriceApi livePriceApi;
    @Resource
    private TradeOrderDeliveryService deliveryService;
    @Resource
    private BankAccountInfoApi bankAccountInfoApi;
    @Resource
    @Lazy
    private TradeOrderQueryService orderQueryService;

    // =================== Order ===================

    @Override
    public AppTradeOrderOrderRespVO orderSettle(Long userId, AppTradeOrderOrderReqVO orderReqVO) {
        // 1. 执行结算流程
        TradeOrderOrderResult orderOrderResult = settleOrder(userId, orderReqVO);
        
        // 2. 转换为响应对象
        return TradeOrderConvert.INSTANCE.convert(orderOrderResult.getCalculateRespBO(),
                                                 orderOrderResult.getAddress());
    }
    
    /**
     * 执行订单结算流程
     * 
     * @param userId 用户ID
     * @param settlementReqVO 结算请求
     * @return 结算结果
     */
    private TradeOrderOrderResult settleOrder(Long userId, AppTradeOrderOrderReqVO settlementReqVO) {
        // 保证旧料重量和下单重量一致
        if (TransactionTypeEnum.PRICE_LOCK_SELL.getType().equals(settlementReqVO.getTransactionType()) ||
            TransactionTypeEnum.EXCHANGE_METAL.getType().equals(settlementReqVO.getTransactionType())) {
            if (settlementReqVO.getWeight() != null && settlementReqVO.getWeight().compareTo(BigDecimal.ZERO) > 0) {
                settlementReqVO.setExchangeWeight(settlementReqVO.getWeight());
            }
            if (settlementReqVO.getExchangeWeight() != null && settlementReqVO.getExchangeWeight().compareTo(BigDecimal.ZERO) > 0) {
                settlementReqVO.setWeight(settlementReqVO.getExchangeWeight());
            }
        }

        TransactionModeHandler handler = transactionModeHandlerFactory.getHandler(settlementReqVO.getTransactionType());

        // 获取收货地址
        MemberAddressRespDTO address = addressApi.getDefaultAddress(userId);

        // 校验用户交易配置
        MemberConfRespDTO memberConf = memberConfApi.getMemberConfByUserId(userId);
        validateTradeConfiguration(handler, memberConf, settlementReqVO);

        // 获取交易配置并设置到计算对象中
        TradePriceCalculateReqBO calculateReqBO = TradeOrderConvert.INSTANCE.convert(userId, settlementReqVO);
        
        // 计算订单价格
        TradePriceCalculateRespBO calculateRespBO = handler.calculatePrice(calculateReqBO);
        
        // 返回结算结果
        return new TradeOrderOrderResult()
                .setAddress(address)
                .setCalculateRespBO(calculateRespBO)
                .setMemberConf(memberConf);
    }
    
    /**
     * 校验用户交易配置
     *
     * @param handler
     * @param memberConf      用户配置
     * @param settlementReqVO 结算请求
     */
    private void validateTradeConfiguration(TransactionModeHandler handler, MemberConfRespDTO memberConf, AppTradeOrderOrderReqVO settlementReqVO) {
        // 1.1 交易模式、交易间隔、交易数量、
        // 全款：自动补定金、自动补定金比例、自动结算比例  免息天数、小额下单、审核即付定金比例
        // 锁价：自动补定金、自动补定金比例、自动结算比例   免息天数、小额下单、
        // 存料：审核即付定金比例()
        // 定金、累计限制、单笔限制、延期费、l工费、免息天数、小额下单、审核即付定金比例

        // 基础校验：用户配置必须存在
        if (memberConf == null) {
            throw exception(ORDER_CREATE_FAIL_USER_CONF_NOT_FOUND);
        }
        
        // 校验交易权限
        handler.validatePermission(memberConf);
        
        // 校验并获取金属配置
        MemberConfMaterialDTO materialConf = handler.validateAndGetMaterialConf(memberConf, settlementReqVO.getMetalType(), settlementReqVO.getTransactionType());
        
        // 校验交易限制
        handler.validateTradeLimits(materialConf, settlementReqVO);

        settlementReqVO.setMetalConf(materialConf);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE)
    public TradeOrderDO createOrder(Long userId, AppTradeOrderOrderCreateReqVO createReqVO) {
        // 1. 执行订单结算流程
        TradeOrderOrderResult settlementResult = settleOrder(userId, createReqVO);
        TradePriceCalculateRespBO calculateRespBO = settlementResult.getCalculateRespBO();
        
        // 2. 创建订单
        TradeOrderCreationContext context = new TradeOrderCreationContext()
                .setUserId(userId)
                .setCreateReqVO(createReqVO)
                .setCalculateRespBO(calculateRespBO)
                .setMemberConf(settlementResult.getMemberConf());
        
        // 3. 构建订单数据
        context.setOrder(buildOrder(context));
        
        // 4. 处理订单创建流程
        return processOrderCreation(context);
    }
    
    /**
     * 构建交易订单对象
     * 
     * @param context 订单创建上下文
     * @return 交易订单
     */
    private TradeOrderDO buildOrder(TradeOrderCreationContext context) {
        Long userId = context.getUserId();
        AppTradeOrderOrderCreateReqVO createReqVO = context.getCreateReqVO();
        TradePriceCalculateRespBO calculateRespBO = context.getCalculateRespBO();
        
        // 1. 构建基础订单信息
        TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, createReqVO, calculateRespBO);
        order.setPointConf(JSONUtil.toJsonStr(createReqVO.getMetalConf().getConfPoints()));
        order.setUserName(getLoginUserName());
        order.setExpireTime(addTime((Duration.ofMinutes(3L))));
        order.setOrderNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX));

        // 2. 设置订单状态
        order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
        
        // 3. 设置支付和退款信息
//        order.setPayStatus(false);

        // 4. 设置物流信息
        TransactionModeHandler handler = transactionModeHandlerFactory.getHandler(order.getOrderType());
        handler.setupDeliveryInfo(order, userId, createReqVO);

        return order;
    }



    
    /**
     * 处理订单创建流程
     * 
     * @param context 订单创建上下文
     * @return 创建的订单
     */
    private TradeOrderDO processOrderCreation(TradeOrderCreationContext context) {
        TradeOrderDO order = context.getOrder();

        AppTradeOrderOrderCreateReqVO createReqVO = context.getCreateReqVO();
        
        // 1. 执行前置处理器
        tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(order));
        
        // 2. 保存订单
        tradeOrderMapper.insert(order);

        // 3. 执行后置处理
        afterCreateTradeOrder(order, createReqVO, context.getCalculateRespBO());
        
        return order;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_PAY)
    public void updateOrderPaid(PayOrderNotifyReqDTO notifyReqDTO) {
        String orderNo = notifyReqDTO.getMerchantOrderId();
        Long payOrderId = notifyReqDTO.getPayOrderId();
        // 1.1 校验订单是否存在
        TradeOrderDO order = validateOrderExists(orderNo);
        // 1.2 校验订单状态
        if (TradeOrderStatusEnum.isCompleted(order.getStatus())) {
            // 特殊：如果订单已完成，直接返回，说明重复回调
            if (ObjectUtil.equals(order.getPayOrderId(), payOrderId)) {
                log.warn("[updateOrderSettled][order({}) 已结算，支付单号{}，直接返回]", order, payOrderId);
                return;
            }
            log.error("[updateOrderSettled][order({}) 支付单不匹配({})，请进行处理！order 数据是：{}]",
                    orderNo, payOrderId, JsonUtils.toJsonString(order));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
        }

        // 2. 校验支付订单的合法性
        PayOrderRespDTO payOrder = validatePayOrderPaid(order, payOrderId);

        // 3. 结算单支付完成
        TransactionModeHandler transactionHandler = transactionModeHandlerFactory.getHandler(order.getOrderType());
        TradeOrderStatusEnum afterStatus = transactionHandler.getNextStatusBySuceess(order, notifyReqDTO.getPayType(), order.getIsStore());
        if (afterStatus == null) {
            afterStatus = TradeOrderStatusEnum.getEnum(order.getStatus());
        }

        order.setStatus(afterStatus.getStatus());

        order.setReceiveDeposit(payOrder.getDeposit());
        order.setReceiveDepositAdd(payOrder.getDepositAdd());
        order.setReceivePrice(payOrder.getTotalPrice());                // 已收金额
        order.setReceiveDelayFee(payOrder.getDelayPrice());
        order.setReceiveProcessFee(payOrder.getProcessPrice());
        order.setReceiveAdditionalFee(payOrder.getAdditionalPrice());
        // 支付单结清 （订单的结算信息在创建结算支付单时更新）
        if (PayOrderStatusEnum.isSettle(payOrder.getStatus())) {
            order.setSettleTime(LocalDateTime.now());
            order.setSettlePrice(livePriceApi.getConfPrice(order.getMetalType(), TransactionTypeEnum.isSale(order.getOrderType())));
            order.setSettlePriceTotal(payOrder.getTotalPrice().add(payOrder.getWaitingPay()).subtract(payOrder.getDeposit()));  // 结算总价 = 已收 + 待支付(欠款) - 定金

            if (!TradeOrderStatusEnum.CLOSED.equals(afterStatus)) {
                order.setReceiveDeposit(BigDecimal.ZERO);
                order.setReceiveDepositAdd(BigDecimal.ZERO);
                // 定金退回
                order.setReceivePrice(payOrder.getTotalPrice().subtract(payOrder.getDeposit()));
                payOrderApi.refundDeposit(payOrder.getId(), order.getUserId());

                // 存料 -> 用户钱包添加
                if (order.getIsStore()) {
                    PayWalletAddBalanceReqDTO walletAddBalanceReqDTO = new PayWalletAddBalanceReqDTO();
                    walletAddBalanceReqDTO.setUserId(order.getUserId());
                    walletAddBalanceReqDTO.setWalletType(PayWalletTypeEnum.getByMetal(MetalTypeEnum.valueOf(order.getMetalType())));
                    walletAddBalanceReqDTO.setBizType(PayWalletBizTypeEnum.getReChargeByMetal(MetalTypeEnum.valueOf(order.getMetalType())));
                    walletAddBalanceReqDTO.setBizId(orderNo);
                    walletAddBalanceReqDTO.setPrice(order.getWeight());

                    payWalletApi.addWalletBalance(walletAddBalanceReqDTO);
                }
            }
        }

        int updateCount = tradeOrderMapper.updateById(order);
        if (updateCount == 0) {
            throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
        }

        // 4. 执行 TradeOrderHandler 的后置处理
        tradeOrderHandlers.forEach(handler -> handler.afterPayOrder(order));

        // 5. 记录订单日志
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), afterStatus.getStatus());
        TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER_PERSON.getValue());
    }

    @Override
    public void syncOrderPayStatusQuietly(Long id, Long payOrderId) {
//        PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
//        if (payOrder == null) {
//            return;
//        }
//        if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
//            return;
//        }
//        try {
//            getSelf().updateOrderCompleted(id, payOrderId);
//        } catch (Throwable e) {
//            log.warn("[syncOrderPayStatusQuietly][id({}) payOrderId({}) 同步支付状态失败]", id, payOrderId, e);
//        }
    }

    /**
     * 校验支付订单的合法性
     *
     * @param order      交易订单
     * @param payOrderId 支付订单编号
     * @return 支付订单
     */
    private PayOrderRespDTO validatePayOrderPaid(TradeOrderDO order, Long payOrderId) {
        // 1. 校验支付单是否存在
        PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
        if (payOrder == null) {
            log.error("[validatePayOrderPaid][order({}) payOrder({}) 不存在，请进行处理！]", order.getOrderNo(), payOrderId);
            throw exception(ORDER_NOT_FOUND);
        }

        // 2.1 校验支付单已完成
        if (payOrder.getWaitingPay().compareTo(BigDecimal.ZERO) > 0) {
            log.error("[validatePayOrderPaid][order({}) payOrder({}) 未支付结算，请进行处理！payOrder 数据是：{}]",
                    order.getOrderNo(), payOrderId, JsonUtils.toJsonString(payOrder));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
        }
        // 2.2 校验支付订单匹配（二次）
        if (ObjectUtil.notEqual(payOrder.getOrderNo(), order.getOrderNo())) {
            log.error("[validatePayOrderPaid][order({}) 支付单不匹配({})，请进行处理！payOrder 数据是：{}]",
                    order.getOrderNo(), payOrderId, JsonUtils.toJsonString(payOrder));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
        }
        return payOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void prepareDone(String orderNo) {
        TradeOrderDO order = validateOrderExists(orderNo);
        order.setStatus(TradeOrderStatusEnum.PREPARE_DONE.getStatus());
        tradeOrderMapper.updateById(order);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_DELIVERY)
    public void deliveryOrder(TradeOrderDeliveryReqVO deliveryReqVO) {
        // 1.1 校验并获得交易订单（可发货）
        TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getOrderNo());
        // 1.2 校验 deliveryType 是否为快递，是快递才可以发货
        if (!ObjectUtils.equalsAny(order.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType(), DeliveryTypeEnum.SHOP_DELIVERY.getType())) {
            throw exception(ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS);
        }

        DeliveryTypeEnum deliveryTypeEnum;
        if (TradeOrderStatusEnum.UNDELIVERED_MEMBER.getStatus().equals(order.getStatus())) {
            deliveryTypeEnum = DeliveryTypeEnum.EXPRESS_TO_SHOP;
            order.setStatus(TradeOrderStatusEnum.WAIT_CHECK.getStatus());
        } else if (TradeOrderStatusEnum.PREPARE_DONE.getStatus().equals(order.getStatus())){
            deliveryTypeEnum = DeliveryTypeEnum.EXPRESS_TO_MEMBER;
            if (DeliveryTypeEnum.SHOP_DELIVERY.getType().equals(deliveryReqVO.getDeliveryType())) {
                deliveryTypeEnum = DeliveryTypeEnum.SHOP_DELIVERY;
            }
            order.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus());
        } else {
            throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
        }
        // 快递发货
//        DeliveryExpressDO express = null;
//        if (ObjectUtil.notEqual(deliveryReqVO.getLogisticsId(), TradeOrderDO.LOGISTICS_ID_NULL)) {
//            express = deliveryExpressService.validateDeliveryExpress(deliveryReqVO.getLogisticsId());
//            updateOrderObj.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
//        } else {
//            // 2.2 无需发货
//            updateOrderObj.setLogisticsId(0L).setLogisticsNo("");
//        }

        // 2. 更新订单快递信息
        TradeOrderDeliveryDO deliveryDO = deliveryService.queryByOrderNoAndType(deliveryReqVO.getOrderNo(), deliveryTypeEnum);
        deliveryDO.setLogisticsNo(deliveryReqVO.getLogisticsNo());
        if (deliveryReqVO.getPics() != null && deliveryReqVO.getPics().size() > 0) {
            deliveryDO.setDeliveryPic(deliveryReqVO.getPics());
        }
        deliveryService.update(deliveryDO);
        // 执行更新

        int updateCount = tradeOrderMapper.updateById(order);
        if (updateCount == 0) {
            throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
        }

        // 3. 记录订单日志
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus(),
                MapUtil.<String, Object>builder().put("deliveryType", DeliveryTypeEnum.EXPRESS.getName())
                        .put("logisticsNo", deliveryReqVO.getLogisticsNo())
                        .put("address", deliveryDO.getDetailAddress()).build());

        deliveryReqVO.setAddress(deliveryDO.getDetailAddress());
        // 4.1 发送站内信
        tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO()
                .setOrderId(order.getOrderNo()).setUserId(order.getUserId()).setMessage(null));
        // 4.2 发送订阅消息
        getSelf().sendDeliveryOrderMessage(order, deliveryReqVO);
    }

    @Async
    public void sendDeliveryOrderMessage(TradeOrderDO order, TradeOrderDeliveryReqVO deliveryReqVO) {
        // 构建并发送模版消息
        String orderId = order.getOrderNo();
        socialClientApi.sendWxaSubscribeMessage(new SocialWxaSubscribeMessageSendReqDTO()
                .setUserId(order.getUserId()).setUserType(UserTypeEnum.MEMBER_PERSON.getValue())
                .setTemplateTitle(WXA_ORDER_DELIVERY)
                .setPage("pages/order/detail?id=" + orderId) // 订单详情页
                .addMessage("character_string3", String.valueOf(orderId)) // 订单编号
                .addMessage("phrase6", TradeOrderStatusEnum.DELIVERED.getName()) // 订单状态
                .addMessage("date4", LocalDateTimeUtil.formatNormal(LocalDateTime.now()))// 发货时间
                .addMessage("character_string5", StrUtil.blankToDefault(deliveryReqVO.getLogisticsNo(), "-")) // 快递单号
                .addMessage("thing9", deliveryReqVO.getAddress()) // 收货地址
        );
    }

    /**
     * 校验交易订单满足被发货的条件
     * <p>
     * 1. 交易订单未发货
     *
     * @param no 交易订单编号
     * @return 交易订单
     */
    private TradeOrderDO validateOrderDeliverable(String no) {
        TradeOrderDO order = validateOrderExists(no);
        // 1. 校验订单是否未发货
//        if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
//            throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
//        }

        // 2. 执行 TradeOrderHandler 前置处理
        tradeOrderHandlers.forEach(handler -> handler.beforeDeliveryOrder(order));
        return order;
    }

    @NotNull
    private TradeOrderDO validateOrderExists(String no) {
        // 校验订单是否存在
        TradeOrderDO order = tradeOrderMapper.selectByNo(no);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        return order;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_RECEIVE)
    public void receiveOrderByMember(Long userId, String orderNo) {
        // 校验并获得交易订单（可收货）
        TradeOrderDO order = validateOrderReceivable(userId, orderNo);

        // 收货订单
        receiveOrder(order);
    }

    @Override
    public void receiveOrderByAdmin(String orderNo) {
        // 校验并获得交易订单（可收货）
        TradeOrderDO order = validateOrderReceivable(null, orderNo);

        // 收货订单
        receiveOrder(order);
    }

    @Override
    public int receiveOrderBySystem() {
        // 1. 查询过期的待支付订单
//        LocalDateTime expireTime = minusTime(tradeOrderProperties.getReceiveExpireTime());
//        List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt(
//                TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime);
//        if (CollUtil.isEmpty(orders)) {
//            return 0;
//        }
//
//        // 2. 遍历执行，逐个取消
//        int count = 0;
//        for (TradeOrderDO order : orders) {
//            try {
//                getSelf().receiveOrderBySystem(order);
//                count++;
//            } catch (Throwable e) {
//                log.error("[receiveOrderBySystem][order({}) 自动收货订单异常]", order.getId(), e);
//            }
//        }
//        return count;
        return 0;
    }

    /**
     * 自动收货单个订单
     *
     * @param order 订单
     */
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_RECEIVE)
    public void receiveOrderBySystem(TradeOrderDO order) {
        receiveOrder(order);
    }

    /**
     * 收货订单的核心实现
     *
     * @param order 订单
     */
    private void receiveOrder(TradeOrderDO order) {
//        if (order.getSettleTime() == null || order.getSettleTime().isAfter(LocalDateTime.now())) {
//            throw exception(ORDER_NO_SETTLED);
//        }

        // 更新 TradeOrderDO 状态为已完成
        order.setStatus(TradeOrderStatusEnum.COMPLETED.getStatus());
        int updateCount = tradeOrderMapper.updateById(order);
        if (updateCount == 0) {
            throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
        }
        // 插入订单日志
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
    }

    /**
     * 校验交易订单满足可售货的条件
     * <p>
     * 1. 交易订单待收货
     *
     * @param userId 用户编号
     * @param id     交易订单编号
     * @return 交易订单
     */
    private TradeOrderDO validateOrderReceivable(Long userId, String id) {
        // 校验订单是否存在
        TradeOrderDO order = tradeOrderMapper.selectOrderByNoAndUserId(id, userId);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 校验订单是否是待收货状态
        if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
            throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
        }
        return order;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
    public void cancelOrderByMember(Long userId, Long id) {
        // 1.1 校验存在
//        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
//        if (order == null) {
//            throw exception(ORDER_NOT_FOUND);
//        }
//        // 1.2 校验状态
//        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
//            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
//        }
//
//        // 2. 取消订单
//        cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
    }

    @Override
    public int cancelUnpaidOrderBySystem() {
        // 1. 查询过期的待支付订单
//        LocalDateTime expireTime = minusTime(tradeOrderProperties.getExpireTime());
        List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
                TradeOrderStatusEnum.UNPAID.getStatus());
        if (CollUtil.isEmpty(orders)) {
            return 0;
        }

        // 2. 遍历执行，逐个取消
        int count = 0;
        for (TradeOrderDO order : orders) {
            try {
                getSelf().cancelOrderBySystem(order);
                count++;
            } catch (Throwable e) {
                log.error("[cancelOrderBySystem][order({}) 过期订单异常]", order.getOrderNo(), e);
            }
        }
        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int rollbackPartPaidOrderBySystem() {
        // 查询结算中,并且支付订单过期的
        List<TradeOrderDO> orders = tradeOrderMapper.selectSettlingAndPayExpireOrder();
        if (CollUtil.isEmpty(orders)) {
            return 0;
        }

        // 2. 遍历执行，逐个取消
        int count = 0;
        for (TradeOrderDO order : orders) {
            try {
                rollbackSettlingOrder(order);
                count++;
            } catch (Throwable e) {
                log.error("[cancelOrderBySystem][order({}) 过期订单异常]", order.getOrderNo(), e);
            }
        }
        return count;
    }

    private void rollbackSettlingOrder(TradeOrderDO order) {
        updateOrderByPayExpire(order.getOrderNo());
        payOrderApi.rollbackPayExpire(order.getPayOrderId());
    }

    /**
     * 自动取消单个订单
     *
     * @param order 订单
     */
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
    public void cancelOrderBySystem(TradeOrderDO order) {
        cancelOrder0(order);
    }

    /**
     * 取消订单的核心实现
     *
     * @param order      订单
     */
    private void cancelOrder0(TradeOrderDO order) {
        order.setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
                .setCancelTime(LocalDateTime.now());
//         1. 更新 TradeOrderDO 状态为已取消
        int updateCount = tradeOrderMapper.updateById(order);
        if (updateCount == 0) {
            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
        }
        // 3. 增加订单日志
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
    }

    /**
     * 如果金额全部被退款，则取消订单
     * 如果还有未被退款的金额，则无需取消订单
     *
     * @param order       订单
     * @param refundPrice 退款金额
     */
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_CANCEL_AFTER_SALE)
    public void cancelOrderByAfterSale(TradeOrderDO order, Integer refundPrice) {
        // 1. 更新订单
//        if (refundPrice < order.getPayPrice()) {
//            return;
//        }
//        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
//                .setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
//                .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now()));
//
//        // 2. 执行 TradeOrderHandler 的后置处理
//        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
//        tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(order, orderItems));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
    public void deleteOrder(Long userId, String no) {
        // 1.1 校验存在
        TradeOrderDO order = tradeOrderMapper.selectOrderByNoAndUserId(no, userId);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 1.2 校验状态
        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
            throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
        }
        // 2. 删除订单
        tradeOrderMapper.deleteById(no);

        // 3. 记录日志
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), order.getStatus());
    }

    @Override
    public void updateOrderRemark(TradeOrderRemarkReqVO reqVO) {
        // 校验并获得交易订单
        validateOrderExists(reqVO.getNo());

        // 更新
//        TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(reqVO);
//        tradeOrderMapper.updateById(order);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_PRICE)
    public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
        // 1.1 校验交易订单
//        TradeOrderDO order = validateOrderExists(reqVO.getId());
//        if (order.getPayStatus()) {
//            throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
//        }
//        // 1.2 校验调价金额是否变化
//        if (order.getAdjustPrice() > 0) {
//            throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY);
//        }
//        // 1.3 支付价格不能为 0
//        int newPayPrice = order.getPayPrice() + reqVO.getAdjustPrice();
//        if (newPayPrice <= 0) {
//            throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR);
//        }
//
//        // 2. 更新订单
//        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
//                .setAdjustPrice(reqVO.getAdjustPrice() + order.getAdjustPrice()).setPayPrice(newPayPrice));
//
//        // 3. 更新 TradeOrderItem，需要做 adjustPrice 的分摊
//        List<TradeOrderItemDO> orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
////        List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, reqVO.getAdjustPrice());
//        List<TradeOrderItemDO> updateItems = new ArrayList<>();
////        for (int i = 0; i < orderOrderItems.size(); i++) {
////            TradeOrderItemDO item = orderOrderItems.get(i);
////            updateItems.add(new TradeOrderItemDO().setId(item.getId())
////                    .setAdjustPrice(item.getAdjustPrice() + dividePrices.get(i))
////                    .setPayPrice(item.getPayPrice() + dividePrices.get(i)));
////        }
//        tradeOrderItemMapper.updateBatch(updateItems);
//
//        // 4. 更新支付订单
//        payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice);
//
//        // 5. 记录订单日志
//        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(),
//                MapUtil.<String, Object>builder().put("oldPayPrice", MoneyUtils.fenToYuanStr(order.getPayPrice()))
//                        .put("adjustPrice", MoneyUtils.fenToYuanStr(reqVO.getAdjustPrice()))
//                        .put("newPayPrice", MoneyUtils.fenToYuanStr(newPayPrice)).build());


//
//        // 1.1 校验交易订单
//        TradeOrderDO order = validateOrderExists(reqVO.getId());
//        if (order.getPayStatus()) {
//            throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
//        }
//        // 计算核验后价格
//        if (reqVO.getAdjustPrice() == 0 && reqVO.getIsCheck()) {
//            TradeOrderItemExpandDO itemExpandDO = tradeOrderItemExpandMapper.selecOneByOrderId(order.getId());
//            long purePrice = MoneyUtils.calculatePrice(itemExpandDO.getLivePriceOrder(), reqVO.getCheckRes().getWeightCheckAfter());
//            long purePercentPrice = MoneyUtils.priceMultiplyPercent(
//                            new BigDecimal(purePrice), new BigDecimal(reqVO.getCheckRes().getPurePercent()))
//                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).longValue();
//            reqVO.setAdjustPrice(purePercentPrice - reqVO.getDeductTotal() - order.getPayPrice());
//        }
////        // 1.2 校验调价金额是否变化
////        if (order.getAdjustPrice() > 0) {
////            throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY);
////        }
//        // 1.3 支付价格不能为 0
//        long newPayPrice = order.getPayPrice() + reqVO.getAdjustPrice();
//        if (newPayPrice <= 0) {
//            throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR);
//        }
//        // 2. 更新订单
//        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
//                .setAdjustPrice(reqVO.getAdjustPrice() + order.getAdjustPrice()).setPayPrice(newPayPrice));
//
//        // 3. 更新 TradeOrderItem，需要做 adjustPrice 的分摊
//        List<TradeOrderItemDO> orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
//        List<Long> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, reqVO.getAdjustPrice());
//        List<TradeOrderItemDO> updateItems = new ArrayList<>();
//        for (int i = 0; i < orderOrderItems.size(); i++) {
//            TradeOrderItemDO item = orderOrderItems.get(i);
//            updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(item.getAdjustPrice() + dividePrices.get(i))
//                    .setPayPrice((item.getPayPrice() - item.getAdjustPrice()) + dividePrices.get(i)));
//        }
//        tradeOrderItemMapper.updateBatch(updateItems);
//
//        // 4. 更新支付订单
//        payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice);
//
//        // 5. 记录订单日志
//        Map<String, Object> logMap = MapUtil.<String, Object>builder().put("oldPayPrice", MoneyUtils.fenToYuanStr(order.getPayPrice()))
//                .put("adjustPrice", MoneyUtils.fenToYuanStr(reqVO.getAdjustPrice()))
//                .put("newPayPrice", MoneyUtils.fenToYuanStr(newPayPrice)).build();
//        if (ObjectUtil.isNotNull(reqVO.getCheckRes())) {
//            logMap.put("pure_percent", MoneyUtils.fenToYuanStr(reqVO.getCheckRes().getPurePercent()));
//            logMap.put("weight_member", MoneyUtils.gTo000g(reqVO.getCheckRes().getWeightMember()));
//            logMap.put("weight_check_before", MoneyUtils.gTo000g(reqVO.getCheckRes().getWeightCheckBefore()));
//            logMap.put("weight_check_after", MoneyUtils.gTo000g(reqVO.getCheckRes().getWeightCheckAfter()));
//            logMap.put("deduct_total", MoneyUtils.fenToYuan(reqVO.getDeductTotal()));
//            logMap.put("deduct_list", reqVO.getDeductString());
//        }
//        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(),logMap);
//        // 更新订单状态
//        if (reqVO.getIsCheck()) {
//            boolean deposit = ObjectUtil.isNotNull(order.getDepositPrice()) && order.getDepositPrice() > 0;
//            TradeOrderStatusHandler statusHandler = OrderStatusHandlerFactory.getHandler(deposit, order.getProductType());
//            if (ObjectUtil.isNull(statusHandler)) {
//                throw exception(new ErrorCode(999999999, "订单错误"));
//            }
//            TradeOrderDO checkedOrder = statusHandler.checkStatus(order, payOrderApi.getOrder(order.getPayOrderId()));
//            int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), checkedOrder);
//
//            if (updateCount == 0) {
//                throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
//            }
//
//            payOrderApi.createOrderExtensionForAdmin(order.getPayOrderId(), order.getPayPrice());
//            // 记录订单日志
//            TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), checkedOrder.getStatus());
//            TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.ADMIN.getValue());
//        }
    }

    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_ADDRESS)
    public void updateOrderAddress(TradeOrderUpdateAddressReqVO reqVO) {
        // 校验交易订单
//        TradeOrderDO order = validateOrderExists(reqVO.getId());
//        // 只有待发货状态，才可以修改订单收货地址；
//        if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
//            throw exception(ORDER_UPDATE_ADDRESS_FAIL_STATUS_NOT_DELIVERED);
//        }
//
//        // 更新
//        tradeOrderMapper.updateById(TradeOrderConvert.INSTANCE.convert(reqVO));
//
//        // 记录订单日志
//        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
    }

    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE)
    public void pickUpOrderByAdmin(Long userId, String pickUpVerifyCode) {
        getSelf().pickUpOrder(userId, tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode));
    }

    @Transactional(rollbackFor = Exception.class)
    public void pickUpOrder(Long userId, TradeOrderDO order) {
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        if (ObjUtil.notEqual(DeliveryTypeEnum.PICK_UP.getType(), order.getDeliveryType())) {
            throw exception(ORDER_RECEIVE_FAIL_DELIVERY_TYPE_NOT_PICK_UP);
        }
//        DeliveryPickUpStoreDO deliveryPickUpStore = pickUpStoreService.getDeliveryPickUpStore(order.getPickUpStoreId());
//        if (deliveryPickUpStore == null
//                || !CollUtil.contains(deliveryPickUpStore.getVerifyUserIds(), userId)) {
//            throw exception(ORDER_PICK_UP_FAIL_NOT_VERIFY_USER);
//        }

        receiveOrder(order);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelPaidOrder(Long userId, String orderId, Integer cancelType) {
        // 1.1 这里校验下 cancelType 只允许拼团关闭；
//        if (ObjUtil.notEqual(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getType(), cancelType)) {
//            return;
//        }
//        // 1.2 检验订单存在
//        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId);
//        if (order == null) {
//            throw exception(ORDER_NOT_FOUND);
//        }
//
//        // 1.3 校验订单是否支付
//        if (!order.getPayStatus()) {
//            throw exception(ORDER_CANCEL_PAID_FAIL, "已支付");
//        }
//        // 1.3 校验订单是否未退款
//        if (ObjUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
//            throw exception(ORDER_CANCEL_PAID_FAIL, "未退款");
//        }
//
//        // 2.1 取消订单
//        cancelOrder0(order, TradeOrderCancelTypeEnum.COMBINATION_CLOSE);
//        // 2.2 创建退款单
//        payRefundApi.createRefund(new PayRefundCreateReqDTO()
//                .setAppKey(tradeOrderProperties.getPayAppKey())  // 支付应用
//                .setUserIp(NetUtil.getLocalhostStr()) // 使用本机 IP，因为是服务器发起退款的
//                .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
//                .setMerchantRefundId(String.valueOf(order.getId()))
//                .setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice())); // 价格信息
    }

    // TODO: 2025/3/21 修改TradeOrderOperateTypeEnum
    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_PAY)
    public AppTradeOrderCreateRespVO createPaySettled(String orderNo, BigDecimal orderWeight, Boolean autoPay, Boolean isStore,
                                                      Boolean isViolate, List<String> payPicUrl, Long collectInfoId, Long bankInfoId) {
        // 校验存在
        TradeOrderDO order = tradeOrderMapper.selectById(orderNo);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 校验状态 todo
//        if (!TradeOrderStatusEnum.canSettle(order.getStatus())) {
//            throw exception(ORDER_SETTLE_FAIL_STATUS_ERROR);
//        }

        PayOrderCreateReqDTO createReqDTO = getSettleInfo(orderNo, orderWeight, isViolate);

        if (createReqDTO != null) {
            if (!isViolate && autoPay && (payPicUrl == null || payPicUrl.isEmpty() || collectInfoId == null)) {
                throw exception(new ErrorCode(99999999, "自动结算失败, 支付凭证截图/收款账户不能为空"));
            }
            // 创建支付单
            createReqDTO.setOrderType(order.getOrderType());
            createReqDTO.setUserId(order.getUserId());
            createReqDTO.setAutoPay(autoPay);
            createReqDTO.setChannelCode(PayChannelEnum.SPEC.getCode());
            if (isViolate && autoPay) {
                createReqDTO.setChannelCode(PayChannelEnum.WALLET.getCode());
            }
            createReqDTO.setPayPicUrl(payPicUrl);
            createReqDTO.setCollectInfoId(collectInfoId);
            createReqDTO.setAppKey(tradeOrderProperties.getPayAppKey());
            payOrderApi.createOrder(createReqDTO);

            // 创建打款单
            if (createReqDTO.getPrice().compareTo(BigDecimal.ZERO) < 0 && bankInfoId != null) {
                BigDecimal toPaymentPrice = BigDecimal.ZERO.subtract(createReqDTO.getPrice());
                BankAccountInfoDTO bankAccountInfo = bankAccountInfoApi.getBankAccountInfo(bankInfoId);
                payOrderApi.createWithDrawBySystem(toPaymentPrice, order.getUserId(), String.valueOf(order.getPayOrderId()),
                        bankAccountInfo.getName(), bankAccountInfo.getBankId(),bankAccountInfo.getBankName(),bankAccountInfo.getBankAddress());
            }

            TradeSettleMethodTypeEnum typeEnum = TradeSettleMethodTypeEnum.getType(getLoginUserType(), isViolate);

            if (TransactionTypeEnum.EXCHANGE_METAL.getType().equals(order.getOrderType()) ||
                    TransactionTypeEnum.PRICE_LOCK_SELL.getType().equals(order.getOrderType())) {
                order.setWeight(orderWeight);
            }
            // 更新订单状态为结算中
            order.setStatus(TradeOrderStatusEnum.SETTLING.getStatus());
            order.setSettleMethod(typeEnum.getType());
            if (isStore != null && isStore) {
                order.setIsStore(isStore);
                order.setDeliveryType(null);
            }
            int updateCount = tradeOrderMapper.updateById(order);
            if (updateCount == 0) {
                throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
            }
            // 记录订单日志
            TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), TradeOrderStatusEnum.SETTLING.getStatus());
            TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER_PERSON.getValue());
        }
        return new AppTradeOrderCreateRespVO().setNo(order.getOrderNo()).setPayOrderId(order.getPayOrderId());
    }

    @Override
    public void updateOrderByCheck(TradeOrderUpdateCheckDTO updateCheck) {
        // 校验交易订单
        TradeOrderDO order = validateOrderExists(updateCheck.getOrderNo());

        // TODO: 2025/4/3 如果核验出的金属类型与下单类型不一致，以核验为准，价格以当前价格为准

        if (TransactionTypeEnum.EXCHANGE_METAL.getType().equals(order.getOrderType()) ||
                TransactionTypeEnum.PRICE_LOCK_SELL.getType().equals(order.getOrderType())) {
            order.setWeight(updateCheck.getConvertWeight());
        }
        // 核验信息
        order.setConvertWeight(updateCheck.getConvertWeight());
        order.setPurity(updateCheck.getPurity());
        order.setDeductPrice(updateCheck.getDeductTotal());
        // 状态：待确认
        int beforeStatus = order.getStatus();
        order.setStatus(TradeOrderStatusEnum.WAIT_CONFIRM.getStatus());

        // 更新订单
        tradeOrderMapper.updateById(order);

        // 记录订单日志
        Map<String, Object> logMap = MapUtil.<String, Object>builder()
                .put("order_weight", order.getWeight())
                .put("exchange_weight", order.getExchangeWeight())
                .put("convert_weight", order.getConvertWeight())
                .put("pure_percent", order.getPurity())
                .put("deduct_total", order.getDeductPrice())
                .put("deduct_list", updateCheck.getDeductString())
                .build();
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), beforeStatus, order.getStatus(),logMap);
        TradeOrderLogUtils.setUserInfo(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
    }

    //  确认核验结果
    //  app ：卖 直接确认结果；旧料兑换：确认最终重量（可输入） --> 创建结算单：
    @Override
    @Transactional
    public AppTradeOrderDetailRespVO confirmCheck(TradeOrderSettleReqVO settleReqVO) {
        settleOrder(settleReqVO);
        // todo 记录日志：用户确认订单 weight：
        // TODO: 2025/4/4 支付单的金额 > 0 跳转支付 ；否则刷新订单信息，等待打款
        return orderQueryService.getOrderDetial(settleReqVO.getOrderNo());
    }

    @Override
    @Transactional
    public Boolean settleOrder(TradeOrderSettleReqVO settleReqVO) {
        /*
        爆仓条件:需补定金+延期费+...   >= 用户余额+可借额度
          锁价(未爆仓):
          1.等同于直接结算: 扣款,通知用户
          旧料兑换:
          1.已经核验  -> 弹窗提示用户已确认? 输入兑换克重
          2.其他  -> 取消订单(弹窗提示)
          ----> 结算单
         */
        if (!settleReqVO.getIsViolate() && settleReqVO.getAutoPay() && (settleReqVO.getPayPicUrl() == null || settleReqVO.getPayPicUrl().isEmpty())) {
            throw exception(new ErrorCode(99999999, "自动结算失败, 支付凭证截图不能为空"));
        }
        createPaySettled(settleReqVO.getOrderNo(), settleReqVO.getOrderWeight(), settleReqVO.getAutoPay(), settleReqVO.getIsStore(),
                settleReqVO.getIsViolate(), settleReqVO.getPayPicUrl(), settleReqVO.getCollectInfoId(), settleReqVO.getBankInfoId());
        // TODO: 2025/4/4 发送短信通知
        return true;
    }

    @Override
    public PayOrderCreateReqDTO getSettleInfo(String orderNo, BigDecimal orderWeight, Boolean isViolate) {
        TradeOrderDO order = tradeOrderMapper.selectByNo(orderNo);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        if (orderWeight != null) {
            if (orderWeight .compareTo(BigDecimal.ZERO) < 0) {
                throw exception(ORDER_WEIGHT_LESS_THAN_ZERO);
            }
            order.setWeight(orderWeight);
        }
        TransactionModeHandler handler = transactionModeHandlerFactory.getHandler(order.getOrderType());
        return handler.creatSettlePay(order, isViolate);
    }

    @Override
    public AppTradeOrderCreateRespVO createPayOrder(String orderNo, BigDecimal price, Integer payType) {
        // 校验存在
        TradeOrderDO order = tradeOrderMapper.selectById(orderNo);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        PayNotifyTypeEnum payTypeEnum = PayNotifyTypeEnum.getEnum(payType);

        if (PayNotifyTypeEnum.ORDER_DEPOSIT.getType().equals(payType)) {
            PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO();
            createReqDTO.setPayType(payTypeEnum.getType());
            createReqDTO.setExpireTime(addTime((Duration.ofDays(1L))));
            createReqDTO.setOrderNo(orderNo);
            createReqDTO.setDeposit(price);
            createReqDTO.setPrice(price);
            createReqDTO.setOrderType(order.getOrderType());
            createReqDTO.setUserId(order.getUserId());
            createReqDTO.setAppKey(tradeOrderProperties.getPayAppKey());
            payOrderApi.createOrder(createReqDTO);
            // 记录订单日志
//            TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), order.getStatus());
//            TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER.getValue());
            return new AppTradeOrderCreateRespVO().setNo(order.getOrderNo()).setPayOrderId(order.getPayOrderId());
        } else {
            throw exception(NOT_SUPPORT);
        }
    }

    @Override
    public Boolean updateOrderByCreatePayCheck(Long payOrderId) {
        // 支付单确认订单
        TradeOrderDO tradeOrderDO = orderQueryService.getOrderByPayOrderId(payOrderId);
        if (tradeOrderDO == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 订单状态修改为已支付待审核
        tradeOrderDO.setStatus(TradeOrderStatusEnum.WAIT_PAY_CHECK.getStatus());
        tradeOrderMapper.updateById(tradeOrderDO);
        return true;
    }

    @Override
    public Boolean updateOrderByCollectRejected(Long id) {
        // 支付单确认订单
        TradeOrderDO tradeOrderDO = orderQueryService.getOrderByPayOrderId(id);
        if (tradeOrderDO == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 订单状态修改为结算中
        tradeOrderDO.setStatus(TradeOrderStatusEnum.SETTLING.getStatus());
        tradeOrderMapper.updateById(tradeOrderDO);
        return true;
    }

    private Boolean updateOrderByPayExpire(String orderNo) {
        // 支付单确认订单
        TradeOrderDO tradeOrderDO = orderQueryService.getOrder(null, orderNo);
        if (tradeOrderDO == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 订单状态修改为结算中
        tradeOrderDO.setStatus(TradeOrderStatusEnum.PART_PAID.getStatus());
        tradeOrderMapper.updateById(tradeOrderDO);
        return true;
    }

    //  web ：创建结算单（确认最后兑换重量）

    @Override
    public void updateOrderPartPaid(String orderNo, Long payOrderId) {
        // 1.1 校验订单是否存在
        TradeOrderDO order = validateOrderExists(orderNo);
        // 1.2 校验订单状态
        if (TradeOrderStatusEnum.isCompleted(order.getStatus())) {
            // 特殊：如果订单已完成，直接返回，说明重复回调
            if (ObjectUtil.equals(order.getPayOrderId(), payOrderId)) {
                log.warn("[updateOrderSettled][order({}) 已结算，支付单号{}，直接返回]", order, payOrderId);
                return;
            }
            log.error("[updateOrderSettled][order({}) 支付单不匹配({})，请进行处理！order 数据是：{}]",
                    orderNo, payOrderId, JsonUtils.toJsonString(order));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
        }

        // 2. 校验支付订单的合法性
        PayOrderRespDTO payOrder = validatePayOrderPaid(order, payOrderId);

        // 3. 结算单支付完成
        TradeOrderStatusEnum afterStatus = TradeOrderStatusEnum.PART_PAID;
        order.setReceiveDeposit(payOrder.getDeposit());


//        TradeSettleMethodTypeEnum typeEnum = TradeSettleMethodTypeEnum.getType(getLoginUserType(), isViolate);
//        int updateCount = tradeOrderMapper.updateByNoAndStatus(orderNo, order.getStatus(), afterStatus.getStatus(), typeEnum.getType());
//        if (updateCount == 0) {
//            throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
//        }


        // 4. 执行 TradeOrderHandler 的后置处理
        tradeOrderHandlers.forEach(handler -> handler.afterPayOrder(order));

        // 5. 记录订单日志
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), order.getStatus(), afterStatus.getStatus());
        TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER_PERSON.getValue());
    }


    // =================== 营销相关的操作 ===================

    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private TradeOrderUpdateServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

    /**
     * 订单创建后，执行后置逻辑
     * <p>
     * 例如说：优惠劵的扣减、积分的扣减、支付单的创建等等
     *
     * @param order           订单
     * @param createReqVO     创建订单请求
     * @param calculateRespBO
     */
    private void afterCreateTradeOrder(TradeOrderDO order, AppTradeOrderOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO) {
        // 1. 执行订单创建后置处理器
        tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(order));

        // 3. 生成支付单
        createPayOrder(order, calculateRespBO);

        // 4. 插入订单日志
        TradeOrderLogUtils.setOrderInfo(order.getOrderNo(), null, order.getStatus());
    }

    private void createPayOrder(TradeOrderDO order, TradePriceCalculateRespBO calculateRespBO) {
        // 创建支付单，用于后续的支付
        PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(order, tradeOrderProperties, calculateRespBO);
//        payOrderCreateReqDTO.setPayType(PayNotifyTypeEnum.ORDER.getType());
        payOrderCreateReqDTO.setExpireTime(addTime(Duration.ofMinutes(3L)));
        if (TransactionTypeEnum.EXCHANGE_METAL.getType().equals(order.getOrderType())) {
            payOrderCreateReqDTO.setAutoPay(true);
            payOrderCreateReqDTO.setChannelCode(PayChannelEnum.WALLET.getCode());
        }
//        else if (TransactionTypeEnum.TAKE_METAL.getType().equals(order.getOrderType())) {
//            payOrderCreateReqDTO.setAutoPay(true);
//            payOrderCreateReqDTO.setChannelCode(PayChannelEnum.WALLET_MATERIAL.getCode());
//        }
        Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO);

        // 更新到交易单上
        tradeOrderMapper.updateById(new TradeOrderDO().setOrderNo(order.getOrderNo()).setPayOrderId(payOrderId));
        order.setPayOrderId(payOrderId);
    }


    @Data
    @Accessors(chain = true)
    private static class TradeOrderOrderResult {
        /**
         * 收货地址
         */
        private MemberAddressRespDTO address;

        /**
         * 用户配置
         */
        private MemberConfRespDTO memberConf;

        /**
         * 价格计算请求
         */
        private TradePriceCalculateReqBO calculateReqBO;

        /**
         * 价格计算结果
         */
        private TradePriceCalculateRespBO calculateRespBO;
    }

    /**
     * 订单创建上下文
     */
    @Data
    @Accessors(chain = true)
    private static class TradeOrderCreationContext {
        /**
         * 用户ID
         */
        private Long userId;

        /**
         * 订单创建请求
         */
        private AppTradeOrderOrderCreateReqVO createReqVO;

        /**
         * 价格计算结果
         */
        private TradePriceCalculateRespBO calculateRespBO;

        /**
         * 用户配置
         */
        private MemberConfRespDTO memberConf;

        /**
         * 订单对象
         */
        private TradeOrderDO order;

        /**
         * 订单项列表
         */
        private List<TradeOrderItemDO> orderItems;
    }

    @Data
    @Accessors(chain = true)
    public static class MetalConf {

        private Integer policyType;

        private Integer metalType;

        private BigDecimal depositWeight;

        private BigDecimal weightSingleLimit;

        private BigDecimal weightTotalLimit;

        private BigDecimal delayFee;

        private BigDecimal processingFee;

        private BigDecimal additionalFee;

        private Integer interestFreeDays;

        private Boolean allowSmallOrder;

        private BigDecimal auditDepositRatio;

        private MemberConfPointRespDTO confPoints;

        private MemberConfRebateRespDTO confRebates;

        private MemberConfAdditionalFeeRespDTO confAdditionalFees;
    }

}
